package com.xinye.opencvdemo

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.xinye.jnitest.JNIUtils
import com.xinye.opencvdemo.utils.ThreadUtils
import com.xinye.opencvdemo.utils.ToastUtils
import kotlinx.android.synthetic.main.activity_main.*
import org.opencv.android.OpenCVLoader
import org.opencv.android.Utils
import org.opencv.core.*
import org.opencv.imgproc.Imgproc
import java.lang.Exception
import kotlin.random.Random

class MainActivity: AppCompatActivity() {

    private var mOpenCVInitCompleted = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        loadOpenCVLibraries()

        testJNI()

        btnConvert?.setOnClickListener {
            if(!mOpenCVInitCompleted){
                ToastUtils.toastShort("请等待OpenCV初始化完成")
                return@setOnClickListener
            }
            ThreadUtils.addIOTask {
                covertRGBAToGray()
            }
        }
    }

    private fun testJNI() {
        try {
            System.loadLibrary("native-lib")
        }catch (e: Exception){
            Log.i("wangheng","load library native-lib error:$e")
        }
        Log.i("wangheng","5 pow 5 is:${JNIUtils.powInt(5,5)}")

        JNIUtils.printByNative("wangheng","wangheng-print log by native~~~")
    }

    private fun loadOpenCVLibraries() {
        ThreadUtils.addIOTask {

            val result = OpenCVLoader.initDebug()
            val resultText = if(result){
                "OpenCv库加载成功"
            }else{
                "OpenCV库加载失败"
            }
            runOnUiThread { ToastUtils.toastShort(resultText) }
            mOpenCVInitCompleted = true
        }
    }

    private fun covertRGBAToGray() {
        val options = BitmapFactory.Options()
        options.inPreferredConfig = Bitmap.Config.ARGB_8888

        val bitmap = BitmapFactory.decodeResource(resources, R.drawable.origin_image_2)
        val src = Mat()
        val result = Mat()
        Utils.bitmapToMat(bitmap, src)
        // 灰度
//        Imgproc.cvtColor(src, result, Imgproc.COLOR_RGBA2GRAY)
        // 高斯模糊
//        Imgproc.GaussianBlur(src,result, Size(13.0,13.0),5.0)
        //
//        Imgproc.blur(src,result,Size(30.0,30.0))
        // 中值模糊(降噪)
//        Imgproc.medianBlur(src,result,33)

        // 自定义核
//        val kernel = Mat(3,3,CvType.CV_16SC1)
//        kernel.put(0,0,0.0,-1.0,0.0,-1.0,5.5,-1.0,0.0,-1.0,0.0)
//        Imgproc.filter2D(src,result,src.depth(),kernel)

        // 膨胀(扩大亮色)
//        val dilate = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE,Size(5.0,5.0))
//        Imgproc.dilate(src,result,dilate)

        // 腐蚀(扩大暗色)
//        val erode = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE,Size(8.0,8.0))
//        Imgproc.erode(src,result,erode)

//        Imgproc.threshold(src,result,100.0,255.0,Imgproc.THRESH_BINARY)
//        Imgproc.threshold(src,result,200.0,255.0,Imgproc.THRESH_TOZERO)
//        Imgproc.threshold(src,result,200.0,255.0,Imgproc.THRESH_TRUNC)
//        Imgproc.threshold(src,result,100.0,255.0,Imgproc.THRESH_BINARY_INV)
//        Imgproc.threshold(src,result,40.0,255.0,Imgproc.THRESH_TOZERO_INV)

//        Imgproc.cvtColor(src,src,Imgproc.COLOR_RGB2GRAY)
//        Imgproc.adaptiveThreshold(src,result,255.0,Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY,3,0.0)

        // ********************* 通过不同高斯模糊半径相减得到边缘 -- 开始
//        val grayMat = Mat()
//        val mat1 = Mat()
//        val mat2 = Mat()
//
//        // 转为灰度图
//        Imgproc.cvtColor(src,grayMat,Imgproc.COLOR_RGB2GRAY)
//        // 高斯模糊
//        Imgproc.GaussianBlur(grayMat,mat1,Size(15.0,15.0),5.0)
//        Imgproc.GaussianBlur(grayMat,mat2,Size(21.0,21.0),5.0)
//
//        // 将两幅模糊图相减
//        val dog = Mat()
//        Core.absdiff(mat1,mat2,dog)
//
//        // 反转二值阈值化
//        Core.multiply(dog,Scalar(100.0),dog)
//        Imgproc.threshold(dog,result,50.0,255.0,Imgproc.THRESH_BINARY_INV)
        // ********************* 通过不同高斯模糊半径相减得到边缘 -- 结束


        // canny
//        val grayMat = Mat()
//        Imgproc.cvtColor(src,grayMat,Imgproc.COLOR_RGB2GRAY)
//        Imgproc.Canny(grayMat,result,10.0,100.0)

//        sobelTest(src,result)

//        harrisTest(src,result)
        houghTransformation(src,result)

        Utils.matToBitmap(result, bitmap)
        runOnUiThread {
            ivResult?.setImageBitmap(bitmap)
        }
    }

    // Sobel梯度检测法
    private fun sobelTest(src: Mat,result: Mat){
        val grayMat = Mat()
        val gradXMat = Mat()
        val gradYMat = Mat()
        val absGradXMat = Mat()
        val absGradYMat = Mat()

        // 转换为灰度Mat
        Imgproc.cvtColor(src,grayMat,Imgproc.COLOR_RGB2GRAY)
        // 计算水平方向梯度
        Imgproc.Sobel(grayMat,gradXMat,CvType.CV_16S,1,0,3,1.0,0.0)
        // 计算垂直方向地图
        Imgproc.Sobel(grayMat,gradYMat,CvType.CV_16S,0,1,3,1.0,0.0)

        // 计算两个方向的上的据对梯度值
        Core.convertScaleAbs(gradXMat,absGradXMat)
        Core.convertScaleAbs(gradYMat,absGradYMat)

        // 计算梯度结果
        Core.addWeighted(absGradXMat,0.5,absGradYMat,0.5,1.0,result)
    }

    // Harris角点检测
    private fun harrisTest(src: Mat, result: Mat) {
        val grayMat = Mat()

        Imgproc.cvtColor(src,grayMat,Imgproc.COLOR_RGB2GRAY)

        val tempMat = Mat()
        // 找出角点
        Imgproc.cornerHarris(grayMat,tempMat,10,3,0.04)

        // 归一化Harris角点的输出
        val normalize = Mat()
        Core.normalize(tempMat,normalize,0.0,255.0,Core.NORM_MINMAX)
        Core.convertScaleAbs(normalize,result)

        // 在新的图像上绘制交点
        val random = Random.Default
        for(i in 0 until normalize.cols()){
            for(j in 0 until normalize.rows()){
                val value = normalize.get(j,i)
                if(value[0] > 150){
                    Imgproc.circle(result,Point(i.toDouble(),j.toDouble()),15,
                        Scalar(random.nextDouble(255.0),12.0)
                    )
                }
            }
        }
    }

    private fun houghTransformation(src: Mat,result: Mat){
        val grayMat = Mat()
        val cannyEdges = Mat()
        val lines = Mat()

        // 图像转成灰度图
        Imgproc.cvtColor(src,grayMat,Imgproc.COLOR_RGB2GRAY)

        //
        Imgproc.Canny(grayMat,cannyEdges,10.0,100.0)

        Imgproc.HoughLinesP(cannyEdges,lines,1.0,Math.PI / 180,50,20.0,20.0)

        result.create(cannyEdges.rows(),cannyEdges.cols(),CvType.CV_8UC1)
        for(i in 0 until lines.cols()){
            val doublePoints = lines.get(0,i)
            val x1 = doublePoints[0]
            val y1 = doublePoints[1]
            val x2 = doublePoints[2]
            val y2 = doublePoints[3]

            val point1 = Point(x1,y1)
            val point2 = Point(x2,y2)

            Imgproc.line(result,point1,point2, Scalar(255.0,0.0,0.0),1)

        }
    }
}